from abc import ABC, abstractmethod
from typing import List, Optional, Dict, Any, Union, BinaryIO, Callable
from datetime import datetime

from .models import LoginCredentials, PersistentLoginInfo, CloudFile, AccountInfo, TrashItem


class CloudStorageClient(ABC):
    """云存储客户端抽象基类，所有网盘客户端必须继承此类"""
    
    def __init__(self):
        self._logged_in = False
        self._persistent_info: Optional[PersistentLoginInfo] = None
    
    @property
    def is_logged_in(self) -> bool:
        """检查是否已登录
        
        Returns:
            bool: 是否已登录
        """
        return self._logged_in
    
    # 四阶段登录方法
    @abstractmethod
    def trigger_login(self, credentials: LoginCredentials) -> str:
        """触发登录接口（第一阶段）
        
        Args:
            credentials: 登录凭据
            
        Returns:
            str: 登录会话标识符
            
        Raises:
            AuthException: 登录触发失败
        """
        pass
    
    @abstractmethod
    def check_login_status(self, session_id: str) -> Optional[PersistentLoginInfo]:
        """检测登录状态接口（第二阶段）
        
        Args:
            session_id: 登录会话标识符
            
        Returns:
            Optional[PersistentLoginInfo]: 登录成功时返回持久化信息，否则返回None
            
        Raises:
            AuthException: 检查登录状态失败
        """
        pass
    
    @abstractmethod
    def serialize_login_info(self) -> str:
        """登录缓存信息序列化成字符串的接口（第三阶段）
        
        Returns:
            str: 序列化后的登录信息字符串
            
        Raises:
            AuthException: 序列化失败
        """
        pass
    
    @abstractmethod
    def restore_login_from_string(self, serialized_info: str) -> bool:
        """登录接口恢复接口（第四阶段）
        
        Args:
            serialized_info: 序列化后的登录信息字符串
            
        Returns:
            bool: 恢复是否成功
            
        Raises:
            AuthException: 恢复登录失败
        """
        pass
    
    @abstractmethod
    def get_account_info(self) -> AccountInfo:
        """获取账户信息
        
        Returns:
            AccountInfo: 账户信息
            
        Raises:
            AuthException: 未登录
        """
        pass
    
    @abstractmethod
    def list_files(self, folder_id: str) -> List[CloudFile]:
        """列出文件
        
        Args:
            folder_id: 文件夹ID，根目录ID由上游使用方定义
            
        Returns:
            List[CloudFile]: 文件列表
            
        Raises:
            AuthException: 未登录
            FileNotFound: 文件夹不存在
        """
        pass
    
    @abstractmethod
    def create_folder(self, name: str, parent_id: str) -> CloudFile:
        """创建文件夹
        
        Args:
            name: 文件夹名称
            parent_id: 父文件夹ID，根目录ID由上游使用方定义
            
        Returns:
            CloudFile: 创建的文件夹信息
            
        Raises:
            AuthException: 未登录
            FileNotFound: 父文件夹不存在
            CloudStorageError: 配额已满
        """
        pass
    
    @abstractmethod
    def upload_file(
        self, 
        file_name: str,
        file_data: bytes,
        parent_id: str,
        overwrite: bool = False,
        progress_callback: Optional[Callable[[int, int], None]] = None

    ) -> CloudFile:
        """上传文件
        
        Args:
            file_name: 文件名
            file_data: 文件数据
            parent_id: 父文件夹ID，根目录ID由上游使用方定义
            overwrite: 是否覆盖同名文件
            progress_callback: 进度回调函数
            
        Returns:
            CloudFile: 上传后的文件信息
            
        Raises:
            AuthException: 未登录
            FileNotFound: 父文件夹不存在
            CloudStorageError: 配额已满或网络错误
        """
        pass
    
    @abstractmethod
    def delete_file(self, file_id: str) -> None:
        """删除文件
        
        Args:
            file_id: 文件ID
            
        Raises:
            AuthException: 未登录
            FileNotFound: 文件不存在
        """
        pass
    
    @abstractmethod
    def move_file(self, file_id: str, new_parent_id: str, folder_id: str = None) -> CloudFile:
        """移动文件
        
        Args:
            file_id: 文件ID
            new_parent_id: 新父文件夹ID，根目录ID由上游使用方定义
            folder_id: 可选，源文件夹ID，用于获取文件信息
            
        Returns:
            CloudFile: 移动后的文件信息
            
        Raises:
            AuthException: 未登录
            FileNotFound: 文件或目标文件夹不存在
        """
        pass
    
    @abstractmethod
    def rename_file(self, file_id: str, new_name: str) -> CloudFile:
        """重命名文件
        
        Args:
            file_id: 文件ID
            new_name: 新文件名
            
        Returns:
            CloudFile: 重命名后的文件信息
            
        Raises:
            AuthException: 未登录
            FileNotFound: 文件不存在
        """
        pass
    
    @abstractmethod
    def get_file_info(self, file_id: str, folder_id: str) -> CloudFile:
        """获取文件信息
        优化：支持在指定文件夹ID下查看文件信息，查询逻辑是扫描该文件夹下的文件列表，查找指定文件ID的文件
        
        Args:
            file_id: 文件ID
            folder_id: 文件夹ID，在该文件夹下查找文件
            
        Returns:
            CloudFile: 文件信息
            
        Raises:
            AuthException: 未登录
            FileNotFound: 文件不存在
        """
        pass
    
    @abstractmethod
    def search_files(self, parent_id: str, query: str) -> List[CloudFile]:
        """搜索文件
        
        Args:
            parent_id: 父文件夹ID，根目录ID由上游使用方定义
            query: 搜索关键词
            
        Returns:
            List[CloudFile]: 搜索结果
            
        Raises:
            AuthException: 未登录
        """
        pass
    
    @abstractmethod
    def list_trash(self) -> List[TrashItem]:
        """列出回收站文件
        
        Returns:
            List[TrashItem]: 回收站文件列表
            
        Raises:
            AuthException: 未登录
        """
        pass
    
    @abstractmethod
    def empty_trash(self) -> None:
        """清空回收站
        
        Raises:
            AuthException: 未登录
        """
        pass
    
    @abstractmethod
    def get_download_url(self, file_id: str) -> str:
        """获取文件下载链接
        
        Args:
            file_id: 文件ID
            
        Returns:
            str: 下载链接
            
        Raises:
            AuthException: 未登录
            FileNotFound: 文件不存在
        """
        pass
    
    @abstractmethod
    def check_fast_upload(self, file_name: str, file_data: bytes) -> bool:
        """检查文件是否可以快速上传（秒传）
        
        Args:
            file_name: 文件名
            file_data: 文件数据
            
        Returns:
            bool: 是否可以快速上传
            
        Raises:
            AuthException: 未登录
        """
        pass
    
    @abstractmethod
    def fast_upload_file(self, file_name: str, file_data: bytes, parent_id: str) -> CloudFile:
        """快速上传文件（秒传）
        
        Args:
            file_name: 文件名
            file_data: 文件数据
            parent_id: 父文件夹ID，根目录ID由上游使用方定义
            
        Returns:
            CloudFile: 上传后的文件信息
            
        Raises:
            AuthException: 未登录
            FileNotFound: 父文件夹不存在
            CloudStorageError: 快速上传失败
        """
        pass